
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>


/*
USB协议详解：
1. USB协议是通用串行总线协议，用于连接计算机和其他设备。
2. USB协议支持多种设备类型，包括键盘、鼠标、打印机、扫描仪、摄像头等。
3. USB协议支持热插拔，即设备可以随时连接或断开，而不会影响计算机的正常运行。
4. USB协议支持多种传输速率，包括低速（1.5Mbps）、全速（12Mbps）和高速（480Mbps）。
5. USB协议支持多种数据传输方式，包括控制传输、批量传输、中断传输和同步传输。

  usb驱动主要包含主机控制器和设备驱动两部分：
  主机控制器：负责与设备进行通信，包括数据传输、设备枚举等。主要用于控制插入的USB设备
  设备驱动：主要用于控制设备如何作为从机与主机通信

*/



/*
USB版本对比：不同的版本，主要就是传输速率不同
USB主从结构：像电脑上插入鼠标，电脑就是主机，鼠标就是从机；所有的USB通信，都是主机发起的，
USB设备的传输类型
    控制传输：这个是双向传输，数据量通常比较小，主要就是USB总线驱动程序用来进行查询、配置和给USB设备发送通用命令的；
    批量传输：主要用于大量数据传输，同时又没有贷款和时间间隔的要求，比如打印机、扫描仪等；
    中断传输：主要用于周期性数据传输，比如鼠标、键盘等；
    同步传输：主要用于音频设备，比如麦克风、音箱等；
USB设备描述符关系：
    一个设备描述符通常由一个或多个配置描述符组成；
    一个配置描述符通常有一个或多个接口描述符组成；
    一个接口描述符通常有一个或多个端点描述符组成；
        设备描述符：描述设备的基本信息，如设备类型、厂商ID、产品ID等。
        配置描述符：描述设备的配置信息，如配置的名称、配置的电源需求，接口数、支持的挂起和恢复能力等
        接口描述符：描述设备的接口信息，如接口的名称、接口的端点数、接口的电源需求等
        端点描述符：描述设备的端点信息，如端点的地址、端点的传输类型、端点的最大包大小等
        字符串描述符：描述设备的字符串信息，如设备的制造商名称、产品名称、序列号等
设备描述符：
struct usb_device_descriptor {
	__u8  bLength; //该结构体大小
	__u8  bDescriptorType; //描述符类型 （此处应为0x01，即设备描述符）
	__le16 bcdUSB; //usb版本号 200 -> USB2.0
	__u8  bDeviceClass; //设备类 
	__u8  bDeviceSubClass; //设备类子类
	__u8  bDeviceProtocol; //设备协议，以上三点都是USB官方定义
	__u8  bMaxPacketSize0; //端点0最大包大小 （只能为8,16,32,64）
	__le16 idVendor; //厂家id
	__le16 idProduct; //产品id
	__le16 bcdDevice; //设备出厂编号
	__u8  iManufacturer; //描述厂商信息的字符串描述符的索引值
	__u8  iProduct; //描述产品信息的字串描述符的索引值
	__u8  iSerialNumber; //描述设备序列号信息的字串描述符的索引值 
	__u8  bNumConfigurations; //可能的配置描述符的数目
} __attribute__ ((packed));
配置描述符：
struct usb_config_descriptor {
	__u8  bLength; //该结构体大小
	__u8  bDescriptorType;//描述符类型（本结构体中固定为0x02)  
 
	__le16 wTotalLength; //该配置下，信息的总长度（包括配置，接口，端点和设备类及厂商定义的描述符）
	__u8  bNumInterfaces; //接口的个数
	__u8  bConfigurationValue; //Set_Configuration命令所需要的参数值，用来选定此配置
	__u8  iConfiguration; //描述该配置的字符串描述的索引值 
	__u8  bmAttributes;//供电模式的选择  
	__u8  bMaxPower;//设备从总线提取的最大电流
} __attribute__ ((packed));
接口描述符：
struct usb_interface_descriptor {
	__u8  bLength;		//该结构体大小
	__u8  bDescriptorType;//接口描述符的类型编号(0x04）
 
	__u8  bInterfaceNumber;  //该接口的编号  
	__u8  bAlternateSetting; //备用的接口描述符编号  
	__u8  bNumEndpoints; //该接口使用的端点数，不包括端点0  
	__u8  bInterfaceClass; //接口类
	__u8  bInterfaceSubClass; //子类
	__u8  bInterfaceProtocol; //协议
	__u8  iInterface;//描述此接口的字串描述表的索引值  
} __attribute__ ((packed));
端点描述符：  除配置使用的端点0（控制端点，一般一个设备只有一个控制端点）为双向端口外，其它均为单向
struct usb_endpoint_descriptor {
	__u8  bLength;        //端点描述符字节数大小（7个字节）
	__u8  bDescriptorType;//端点描述符类型编号（0x05) 
 
	__u8  bEndpointAddress; //此描述表所描述的端点的地址、方向 : 
                            // bit3~bit0:端点号，bit6~bit4:保留，
                            // bit7:方向，如果是控制端点则忽略，0-输出端点（主机到设备）1-输入端点（设备到主机）
	__u8  bmAttributes; // 端点特性，bit1~bit0 表示传输类型，其他位保留
                        // 00-控制传输  01-实时传输   10-批量传输 11-中断传输
	__le16 wMaxPacketSize;  //端点收、发的最大包大小
	__u8  bInterval; // 中断传输模式中主机查询端点的时间间隔。
                     // 对于实时传输的端点此域必需为1，表示周期为1ms。对于中断传输的端点此域值的范围为1ms到255ms
	__u8  bRefresh;
	__u8  bSynchAddress;
} __attribute__ ((packed));


USB的数据传输对象：
    端点，一个USB设备可以有多个端点，和主机间的数据传输称为到设备端点的数据传输，就比如一个U盘，把数据写到U盘需要一个端点；将U盘的数据读取出来，也是一个端点
*/



/*
USB Core：USB是基于 总线--驱动--设备 模型的框架
    Linux启动阶段，通过subsys_initcall会完成USB Core的加载
    retval = bus_register(&usb_bus_type);    // 注册USB总线；使用bus_register接口注册USB总线，会创建出两条链表用来分别存放向USB总线注册的设备和驱动
    retval = usb_register(&usbfs_driver);    // 在usb总线基础上注册USB接口驱动，该驱动被放在usb总线的驱动链表中
    retval = usb_hub_init();    //初始化一个USB设备集线器，用来检测USB设备的连接和断开（通过初始化的时候创建一个线程进行循环检测）。
    retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);  // 在usb总线注册USB设备驱动，该驱动被放在usb总线的驱动链表中
USB core注册了一个USB总线，并向USB总线中注册了三个驱动，分别是USB接口驱动、HUB驱动、USB设备驱动。
    其中在注册HUB驱动前创建了一个hub_thread线程，用来处理hub上USB设备事件，比如插入和拔出；在HUB驱动的probe函数中，
    创建了一个urb并为其注册了一个中断处理函数hub_irq，用来唤醒hub_thread线程来处理USB设备事件。


USB HCD：

*/


/*
    实现一个USB设备驱动程序：
*/

static struct input_dev *uk_dev;
static char *usb_buf;
static dma_addr_t usb_buf_phys;
static int len;
static struct urb *uk_urb;

static struct usb_device_id usbmouse_as_key_id_table [] = {
	// 匹配HID，鼠标设备
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_MOUSE) },
	//{USB_DEVICE(0x1234,0x5678)},
	{ }	/* Terminating entry */
};

static void usbmouse_as_key_irq(struct urb *urb)
{
	static unsigned char pre_val;

	/* USB鼠标数据含义
	 * data[0]: bit0-左键, 1-按下, 0-松开
	 *          bit1-右键, 1-按下, 0-松开
	 *          bit2-中键, 1-按下, 0-松开 
	 *
     */

	if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
	{
		/* 左键发生了变化 */
		input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
		input_sync(uk_dev);
	}

	if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
	{
		/* 右键发生了变化 */
		input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
		input_sync(uk_dev);
	}

	if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
	{
		/* 中键发生了变化 */
		input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1<<2)) ? 1 : 0);
		input_sync(uk_dev);
	}
	
	pre_val = usb_buf[0];

	/* 重新提交urb */
	usb_submit_urb(uk_urb, GFP_KERNEL);
}

static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	struct usb_host_interface *interface;
	struct usb_endpoint_descriptor *endpoint;
	int pipe;
	
	interface = intf->cur_altsetting;
	endpoint = &interface->endpoint[0].desc;

	/* 分配一个input_dev */
	uk_dev = input_allocate_device();
	
	/* 设置 */
	/* 1 能产生哪类事件 */
	set_bit(EV_KEY, uk_dev->evbit);
	set_bit(EV_REP, uk_dev->evbit);
	
	/* 2 能产生哪些事件 */
	set_bit(KEY_L, uk_dev->keybit);
	set_bit(KEY_S, uk_dev->keybit);
	set_bit(KEY_ENTER, uk_dev->keybit);
	
	/*  注册 */
	input_register_device(uk_dev);
	
	/*  硬件相关操作 */
	/* 数据传输3要素: 源,目的,长度 */
	/* 源: USB设备的某个端点 */

	// 创建数据传输管道
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

	/* 长度: */
	len = endpoint->wMaxPacketSize;

	/* 目的: */
	usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);

	/* 使用"3要素" */
	/* 分配usb request block */
	uk_urb = usb_alloc_urb(0, GFP_KERNEL);
	/* 使用"3要素设置urb" */
	// 初始化urb数据结构
	usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
	uk_urb->transfer_dma = usb_buf_phys;
	uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	/* 使用URB */
	// 提交urb，以读取usb设备数据。
	usb_submit_urb(uk_urb, GFP_KERNEL);
	
	return 0;
}

static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
	struct usb_device *dev = interface_to_usbdev(intf);

	//printk("disconnect usbmouse!\n");
	usb_kill_urb(uk_urb);
	usb_free_urb(uk_urb);

	usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
	input_unregister_device(uk_dev);
	input_free_device(uk_dev);
}

/* 1. 分配/设置usb_driver */
static struct usb_driver usbmouse_as_key_driver = {
	.name		= "usbmouse_as_key_",
	.probe		= usbmouse_as_key_probe,
	.disconnect	= usbmouse_as_key_disconnect,
	.id_table	= usbmouse_as_key_id_table,
};


static int usbmouse_as_key_init(void)
{
	/* 2. 注册 */
	usb_register(&usbmouse_as_key_driver);
	return 0;
}

static void usbmouse_as_key_exit(void)
{
	usb_deregister(&usbmouse_as_key_driver);	
}

module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);

MODULE_LICENSE("GPL");


